package com.xiaoyudeguang.auth.aspect;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import com.xiaoyudeguang.annotations.RequestMapping;
import com.xiaoyudeguang.annotations.RestController;
import com.xiaoyudeguang.util.ProxyUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

/**
 * @author mac
 */
@Aspect
@Configuration
@ConditionalOnBean(StpInterface.class)
public class AuthAspect {

    private static final String FROM = "from";

    @Autowired
    private StpInterface stpInterface;

    @Around("@annotation(requestMapping)")
    public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        if (!requestMapping.checkAuth()) {
            return pjp.proceed();
        }
        if (targetMethod.getAnnotation(SaIgnore.class) != null) {
            return pjp.proceed();
        }
        Object original = ProxyUtils.getTarget(pjp.getTarget());
        if (original.getClass().getAnnotation(SaIgnore.class) != null) {
            return pjp.proceed();
        }
        String permission = null;
        RestController restController = original.getClass().getDeclaredAnnotation(RestController.class);
        SaCheckPermission classCheckPermission = original.getClass().getDeclaredAnnotation(SaCheckPermission.class);
        if (classCheckPermission != null) {
            permission = classCheckPermission.value()[0];
        } else if (restController != null && StringUtils.isNotBlank(restController.permission())) {
            permission = restController.permission();
        } else {
            permission = restController.value().substring(1);
        }
        if (stpInterface.getPermissionList(StpUtil.getLoginId(), StpUtil.getLoginType()).contains(permission + ".*")) {
            return pjp.proceed();
        }
        String methodPermission = requestMapping.permission();
        if (StringUtils.isBlank(methodPermission)) {
            methodPermission = requestMapping.value();
        }
        SaCheckPermission methodCheckPermission = targetMethod.getAnnotation(SaCheckPermission.class);
        if (methodCheckPermission != null && methodCheckPermission.value().length > 0) {
            methodPermission = methodCheckPermission.value()[0];
        }
        permission = permission + "/" + methodPermission;
        if (StringUtils.isBlank(permission)) {
            return pjp.proceed();
        }
        permission = permission.replaceAll("//", ".").replaceAll("/", ".");
        if (!stpInterface.getPermissionList(StpUtil.getLoginId(), StpUtil.getLoginType()).contains(permission)) {
            throw new NotPermissionException(permission);
        }
        return pjp.proceed();
    }

}
